package cim2;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.googlecode.fannj.ActivationFunction;
import com.googlecode.fannj.Layer;

public class Main {
	
	public static void main(String[] args) {
		
		Config cfg = null;
		try {
			cfg = loadConfig();
		} catch (IOException e1) {
			System.out.println("No se pudo cargar el archivo de configuracion config.properties");
			return;
		}			
		
		System.setProperty("jna.library.path", cfg.getFannLibPath());
		
		System.out.println(System.getProperty("jna.library.path")); //maybe the path is malformed
		File file = new File(System.getProperty("jna.library.path") + "fannfloat.dll");
		System.out.println("Is the dll file there: " + file.exists());
		String absolutePath = file.getAbsolutePath();
		System.out.println("Path to fannfloat.dll: " + absolutePath);

		if (!file.exists()){
			System.out.println("No se encuentra la libreria fannfloat.dll");
			return;
		}
		
		System.load(absolutePath);		
		
		boolean salir = false;		
		printMenu();
		
		while (!salir){
			try {
				char c = (char) System.in.read();
				
				if ('t' == c){
					// Entrenar la red
					TrainNet e = new TrainNet(cfg);
					e.test();
					printMenu();
				} else if ('r' == c){
					// Correr la red entrenada con el set de datos de prueba
					RunNet r = new RunNet(cfg);
					r.test();	
					printMenu();
				} else if ('v' == c){
					mostrarRedes(cfg);
					printMenu();
				}
				else if ('q' == c){
					// Salir del programa
					salir = true;
				}
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println("Hubo un error. Fin del programa");
			}
		}		
	}
	
	private static void mostrarRedes(Config cfg){
		for (RedParam r : cfg.getRedes()){
			System.out.println("Nombre: " + r.getNombre());
			System.out.println("Ciclos: " + r.getCiclos());
			System.out.println("Imprimir Cada: " + r.getImprimirCada());
			for (Layer l : r.getCapas()){
				System.out.println("	Neuronas: " + l.size() + " - Funcion: " + l.get(0).getActivationFunction().name() + " - Step: " + l.get(0).getSteepness());
			}			
		}		
	}
	
	private static void printMenu(){
		System.out.println("#########################");
		System.out.println("Elija una opcion: ");
		System.out.println("t: Modo entrenamiento");
		System.out.println("r: Modo ejecucion");
		System.out.println("v: Ver Redes");
		System.out.println("q: Salir");		
	}
	
	private static void loadTopologies(Config cfg) throws IOException{
		Properties prop = new Properties();
		InputStream input = null;
		try {	 
			input = new FileInputStream("./conf/" + cfg.getTopologyFile());
			
			// load a properties file
			prop.load(input);
			
			boolean fin = false;
			List<RedParam> redes = new ArrayList<RedParam>();			
			
			for (int i = 1; !fin; i++){
				String redKey = "r" + String.valueOf(i);
				
				// get the property value and print it out
				String name = prop.getProperty(redKey + ".nombre");
				
				if (name != null){
					RedParam red = new RedParam();
					red.setNombre(name);
					List<Layer> layers = new ArrayList<Layer>();
					
					System.out.println("Procesando red: " + name);					
					String ciclosStr = prop.getProperty(redKey + ".ciclos");
					if (ciclosStr != null){
						red.setCiclos(Integer.parseInt(ciclosStr));
					}
										
					String imprimirCadaStr = prop.getProperty(redKey + ".imprimirCada");
					if (imprimirCadaStr != null){
						red.setImprimirCada(Integer.parseInt(imprimirCadaStr));
					}
					
					String entradaNeuronasStr = prop.getProperty(redKey + ".entrada.neuronas");
					Layer entrada = Layer.create(Integer.parseInt(entradaNeuronasStr));
					layers.add(entrada);
					
					boolean hayOcultas = true;
					for (int j = 1; hayOcultas; j++){
						String ocultaKey = redKey + ".oculta" + String.valueOf(j);
						String ocultaNeuronasStr = prop.getProperty(ocultaKey + ".neuronas");
						Layer oculta = null;

						if (ocultaNeuronasStr == null){
							hayOcultas = false;
						} else {							
							String ocultaFuncion = prop.getProperty(ocultaKey + ".funcion");
							if ("LINEAR".equals(ocultaFuncion)){
								oculta = Layer.create(Integer.parseInt(ocultaNeuronasStr), ActivationFunction.FANN_LINEAR);
							} else if ("SYMMETRIC".equals(ocultaFuncion)){
								oculta = Layer.create(Integer.parseInt(ocultaNeuronasStr), ActivationFunction.FANN_SIGMOID_SYMMETRIC);
							} else {
								oculta = Layer.create(Integer.parseInt(ocultaNeuronasStr));
							}						
						}
						if (oculta != null){
							layers.add(oculta);
						}
					}
					
					String salidaNeuronasStr = prop.getProperty(redKey + ".salida.neuronas");
					String salidaFuncion = prop.getProperty(redKey + ".salida.funcion");					
					Layer salida = null;
					
					if ("LINEAR".equals(salidaFuncion)){
						salida = Layer.create(Integer.parseInt(salidaNeuronasStr), ActivationFunction.FANN_LINEAR);
					} else if ("SYMMETRIC".equals(salidaFuncion)){
						salida = Layer.create(Integer.parseInt(salidaNeuronasStr), ActivationFunction.FANN_SIGMOID_SYMMETRIC);
					} else {
						salida = Layer.create(Integer.parseInt(salidaNeuronasStr));
					}
					
					layers.add(salida);
					
					red.setCapas(layers);					
					redes.add(red);					
				} else {
					// No hay mas redes en el archivo
					fin = true;
				}				
			}
			
			cfg.setRedes(redes);
			
		} finally {
			if (input != null) {
				input.close();
			}
		}
	}
	
	private static Config loadConfig() throws IOException{
		Properties prop = new Properties();
		InputStream input = null;
		Config c = new Config();
		
		try {	 
			input = new FileInputStream("./conf/config.properties");
			
			// load a properties file
			prop.load(input);
	 
			// get the property value and print it out
			String df = prop.getProperty("dataFile");
			System.out.println("Data File: " + df);
			c.setDataFile(df);
			
			String tf = prop.getProperty("topologyFile");
			System.out.println("Topology File: " + tf);
			c.setTopologyFile(tf);
			
			String flp = prop.getProperty("fannLibPath");
			System.out.println("Fann Lib Path: " + flp);
			c.setFannLibPath(flp);

			String std = prop.getProperty("showTestData");
			System.out.println("Show Test Data: " + std);
			c.setShowTestData(Boolean.parseBoolean(std));	

			String stdet = prop.getProperty("showTestDetail");
			System.out.println("Show Test Detail: " + stdet);
			c.setShowTestDetail(Boolean.parseBoolean(stdet));
			
			loadTopologies(c);
			
			return c;
		} finally {
			if (input != null) {
				input.close();
			}
		}
	}
}
